package ca.tatham.triplipse.views.table;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ColumnLayoutData;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;

import ca.tatham.triplipse.Activator;
import ca.tatham.triplipse.RdfStatement;
import ca.tatham.triplipse.views.IRdfStatementLabelProvider;
import ca.tatham.triplipse.views.RdfDocumentContentProvider;
import ca.tatham.triplipse.views.RdfDocumentView;

/**
 * This sample class demonstrates how to plug-in a new workbench view. The view
 * shows data obtained from the model. The sample creates a dummy model on the
 * fly, but a real implementation would connect to the model available either in
 * this or another plug-in (e.g. the workspace). The view is connected to the
 * model using a content provider.
 * <p>
 * The view uses a label provider to define how model objects should be
 * presented in the view. Each view can present the same model objects using
 * different labels and icons, if needed. Alternatively, a single label provider
 * can be shared between views in order to ensure that objects of the same type
 * are presented in the same way everywhere.
 * <p>
 */

public class TableRdfDocumentView extends RdfDocumentView {

	public static final String VIEW_ID = "ca.tatham.triplipse.views.TableRdfDocumentView";
	private static final String SORT_STATE_SETTINGS = "RdfStatementSortState";
	private static final String COLUMN_SUBJECT = "Subject";
	private static final String COLUMN_PREDICATE = "Predicate";
	private static final String COLUMN_OBJECT = "Object";

	private final String columnHeaders[] = { COLUMN_SUBJECT, COLUMN_PREDICATE,
			COLUMN_OBJECT };

	private ColumnLayoutData columnLayouts[] = { new ColumnWeightData(100),
			new ColumnWeightData(100), new ColumnWeightData(100) };

	private SortByAction sortBySubjectAction;
	private SortByAction sortByPredicateAction;
	private SortByAction sortByObjectAction;
	private ChangeSortDirectionAction sortAscendingAction;
	private ChangeSortDirectionAction sortDescendingAction;

	public TableRdfDocumentView() {
		// do nothing
	}

	protected StructuredViewer createViewer(Composite parent) {
		return new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
	}

	@Override
	protected ViewerSorter createSorter() {
		return new RdfStatementSorter();
	}

	@Override
	protected RdfDocumentContentProvider createContentProvider() {
		return new TableRdfDocumentContentProvider();
	}

	@Override
	protected IRdfStatementLabelProvider createLabelProvider() {
		return new TableRdfStatementLabelProvider();
	}

	@Override
	protected RdfStatement getStatementFromSelection(Object selectedObject) {
		// The elements of the table are the statements themselves
		return (RdfStatement) selectedObject;
	}

	private void makeColumns(final Table table, final RdfStatementSorter sorter) {
		SelectionListener headerListener = new SelectionAdapter() {
			/**
			 * Handles the case of user selecting the header area.
			 * <p>
			 * If the column has not been selected previously, it will set the
			 * sorter of that column to be the current tasklist sorter. Repeated
			 * presses on the same column header will toggle sorting order
			 * (ascending/descending).
			 */
			public void widgetSelected(SelectionEvent e) {
				// column selected - first column doesn't count
				int column = table.indexOf((TableColumn) e.widget);
				if (column == sorter.getTopPriority()) {
					sorter.reverseTopPriority();
				} else {
					sorter.setTopPriority(column);
				}
				updateSortState(sorter);
				getViewer().refresh();
				IDialogSettings workbenchSettings = Activator.getDefault()
						.getDialogSettings();
				IDialogSettings settings = workbenchSettings
						.getSection(SORT_STATE_SETTINGS);
				if (settings == null) {
					settings = workbenchSettings
							.addNewSection(SORT_STATE_SETTINGS);
				}
				sorter.saveState(settings);
			}
		};

		TableLayout layout = new TableLayout();
		table.setLayout(layout);
		table.setHeaderVisible(true);
		for (int i = 0; i < columnHeaders.length; i++) {
			layout.addColumnData(columnLayouts[i]);
			TableColumn column = new TableColumn(table, SWT.NONE, i);
			column.setResizable(columnLayouts[i].resizable);
			column.setText(columnHeaders[i]);
			column.addSelectionListener(headerListener);
		}
	}

	@Override
	protected void fillLocalToolBarAdditional(@SuppressWarnings("unused")
	IToolBarManager manager) {
		// do nothing
	}

	@Override
	protected void fillContextMenuAdditional(@SuppressWarnings("unused")
	IMenuManager manager) {
		// do nothing
	}

	protected void fillLocalPullDownAdditional(IMenuManager menu) {
		menu.add(sortBySubjectAction);
		menu.add(sortByPredicateAction);
		menu.add(sortByObjectAction);
	}

	@Override
	protected void makeAdditionalActions() {
		RdfStatementSorter sorter = (RdfStatementSorter) getSorter();
		makeColumns(((TableViewer) getViewer()).getTable(), sorter);
		makeSortByActions(sorter);
		makeSortDirectionActions(sorter);
	}

	private void makeSortDirectionActions(RdfStatementSorter sorter) {
		sortAscendingAction = new ChangeSortDirectionAction(sorter,
				RdfStatementSorter.DIRECTION_ASCENDING);
		sortAscendingAction
				.setText(RdfStatementSorter.SortDirectionAscending_text);

		sortDescendingAction = new ChangeSortDirectionAction(sorter,
				RdfStatementSorter.DIRECTION_DESCENDING);
		sortDescendingAction
				.setText(RdfStatementSorter.SortDirectionDescending_text);
	}

	private void makeSortByActions(RdfStatementSorter sorter) {
		sortBySubjectAction = new SortByAction(sorter,
				RdfStatementSorter.SUBJECT);
		sortBySubjectAction.setText(COLUMN_SUBJECT);

		sortByPredicateAction = new SortByAction(sorter,
				RdfStatementSorter.PREDICATE);
		sortByPredicateAction.setText(COLUMN_PREDICATE);

		sortByObjectAction = new SortByAction(sorter, RdfStatementSorter.OBJECT);
		sortByObjectAction.setText(COLUMN_OBJECT);
	}

	void showMessage(String message) {
		MessageDialog.openInformation(getViewer().getControl().getShell(),
				"Triples Table", message);
	}

	void updateSortState(RdfStatementSorter sorter) {
		int column = sorter.getTopPriority();
		sortBySubjectAction.setChecked(column == RdfStatementSorter.SUBJECT);
		sortByPredicateAction
				.setChecked(column == RdfStatementSorter.PREDICATE);
		sortByObjectAction.setChecked(column == RdfStatementSorter.OBJECT);

		int direction = sorter.getTopPriorityDirection();
		sortAscendingAction
				.setChecked(direction == RdfStatementSorter.DIRECTION_ASCENDING);
		sortDescendingAction
				.setChecked(direction == RdfStatementSorter.DIRECTION_DESCENDING);
	}

	class SortByAction extends Action {

		private static final String SETTINGS_SECTION_TRIPLE_SORT_STATE = "ca.tatham.triplipse.tripletable.SortState"; //$NON-NLS-1$

		private final int column;

		private final RdfStatementSorter sorter;

		/**
		 * @param column
		 */
		public SortByAction(RdfStatementSorter aSorter, int aColumn) {
			this.sorter = aSorter;
			this.column = aColumn;
		}

		public void run() {
			sorter.setTopPriority(column);
			updateSortState(sorter);
			getViewer().refresh();
			IDialogSettings settings = createSortStateSection();
			sorter.saveState(settings);
		}

		private IDialogSettings createSortStateSection() {
			IDialogSettings workbenchSettings = Activator.getDefault()
					.getDialogSettings();
			IDialogSettings settings = workbenchSettings
					.getSection(SETTINGS_SECTION_TRIPLE_SORT_STATE);
			if (settings == null) {
				settings = workbenchSettings
						.addNewSection(SETTINGS_SECTION_TRIPLE_SORT_STATE);
			}
			return settings;
		}
	}

	class ChangeSortDirectionAction extends Action {

		private final int direction;

		private final RdfStatementSorter sorter;

		public ChangeSortDirectionAction(RdfStatementSorter aSorter,
				int aDirection) {
			this.sorter = aSorter;
			this.direction = aDirection;
		}

		public void run() {
			sorter.setTopPriorityDirection(direction);
			updateSortState(sorter);
			getViewer().refresh();
			IDialogSettings workbenchSettings = Activator.getDefault()
					.getDialogSettings();
			IDialogSettings settings = workbenchSettings
					.getSection(SORT_STATE_SETTINGS);
			if (settings == null) {
				settings = workbenchSettings.addNewSection(SORT_STATE_SETTINGS);
			}
			sorter.saveState(settings);
		}
	}

}